package com.spzx.auth.service;


import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.spzx.common.core.constant.CacheConstants;
import com.spzx.common.core.constant.SecurityConstants;
import com.spzx.common.core.constant.UserConstants;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.common.core.utils.JwtUtils;
import com.spzx.common.core.utils.StringUtils;
import com.spzx.common.core.utils.ip.IpUtils;
import com.spzx.common.core.utils.uuid.IdUtils;
import com.spzx.common.redis.service.RedisService;
import com.spzx.common.security.utils.SecurityUtils;
import com.spzx.user.api.RemoteUserService;
import com.spzx.user.domain.UserInfo;
import com.spzx.user.domain.UserRegisterDTO;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;


@Component
public class H5Service {
    @Resource
    StringRedisTemplate stringRedisTemplate;

    @Resource
    RemoteUserService remoteUserService;

    @Resource
    RedisService redisService;


    //注册
    public void register(UserRegisterDTO userRegisterDTO) {
        // 1、校验参数格式
        //用户名或者密码不存在    抛出异常
        String username = userRegisterDTO.getUsername();
        String password = userRegisterDTO.getPassword();

        if (StringUtils.isAnyBlank(username,password)){
            throw new ServiceException("用户和密码不能为空");
        }
        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
                || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
        {
            throw new ServiceException("密码长度必须在5到20个字符之间");
        }

        //2、校验注册验证码
        //验证码的作痛：减少直接操作数据库的请求、保证用户信息的准确性（手机号）
        String codeKey = "spzx:user:code:code:"+userRegisterDTO.getUsername();
        //根据key去将验证码查出来 如果查询结果是空 或者查出的验证码与输入的不正确 则抛出异常
        String redisCode = stringRedisTemplate.opsForValue().get(codeKey);
        if(!StringUtils.hasText(redisCode)||!redisCode.equals(userRegisterDTO.getCode())){
            throw  new ServiceException("验证码错误请重新输入");
        }

        //远程调用 完成注册业务

        R r = remoteUserService.saveUserInfo(userRegisterDTO);
        if (r.getCode()!=200){
            throw new ServiceException("远程调用失败");
        }


    }


    public UserInfo login(UserRegisterDTO userRegisterDTO) {
        String username = userRegisterDTO.getUsername();
        String password = userRegisterDTO.getPassword();
        // 用户名或密码为空 错误
        if (StringUtils.isAnyBlank(username, password))
        {
            throw new ServiceException("用户/密码必须填写");
        }
        // 密码如果不在指定范围内 错误
        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
                || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
        {
            throw new ServiceException("用户密码不在指定范围");
        }
        // 用户名不在指定范围内 错误
        if (username.length() < UserConstants.USERNAME_MIN_LENGTH
                || username.length() > UserConstants.USERNAME_MAX_LENGTH)
        {
            throw new ServiceException("用户名不在指定范围");
        }
        // 1、根据账号查询会员用户信息
        R<UserInfo> userResult = remoteUserService.getUserInfo(username);
        //远程调用失败
        if (R.FAIL == userResult.getCode())
        {
            throw new ServiceException(userResult.getMsg());
        }
        // 账号不存在
        if (ObjectUtils.isEmpty(userResult) || StringUtils.isNull(userResult.getData()))
        {
            throw new ServiceException("登录用户：" + username + " 不存在");
        }
        //可以将一个对象转为另一个类型的对象-> 先将对象转为json字符串  再将json字符串转为另一个类型的对象

        ObjectMapper objectMapper = new ObjectMapper();
        //将远程调用查询到的Map，转为UserInfo对象
        UserInfo userInfo = userResult.getData();// objectMapper.convertValue(userResult.getData() , UserInfo.class);

        if ( !userInfo.getStatus().equals(1)) //会员状态校验
        {
            throw new ServiceException("对不起，您的账号：" + username + " 已禁用");
        }
        //2、校验密码
        //需要使用之前加密的工具类校验密码： 参数1：客户端登录提交的明文密码，参数2：数据库查询到的密文密码
        boolean b = SecurityUtils.matchesPassword(password, userInfo.getPassword());
        if(!b){
            throw new ServiceException("密码错误");
        }

        // 更新登录信息(客户端ip和最后登录时间)
        return userInfo;
    }

    public Map<String, Object> createToken(UserInfo userInfo) {

        String token = IdUtils.fastUUID();
        Long userId = userInfo.getId();
        String userName = userInfo.getUsername();

        // Jwt存储信息
        Map<String, Object> claimsMap = new HashMap<String, Object>();
        claimsMap.put(SecurityConstants.USER_KEY, token);
        claimsMap.put(SecurityConstants.DETAILS_USER_ID, userId);
        claimsMap.put(SecurityConstants.DETAILS_USERNAME, userName);

        // 接口返回信息
        // 通过响应体json携带jwttoken ： {"access_token":jwt , "expires_in":720}
        Map<String, Object> rspMap = new HashMap<String, Object>();
        rspMap.put("access_token", JwtUtils.createToken(claimsMap));
        rspMap.put("expires_in", CacheConstants.EXPIRATION);

        //缓存登录状态到redis中: 网关会校验登录状态
        redisService.setCacheObject(CacheConstants.LOGIN_TOKEN_KEY + token, userInfo, CacheConstants.EXPIRATION, TimeUnit.MINUTES);
        return rspMap;
    }
}
